﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.TestManagement.Client;
using OfficeOpenXml;
using OfficeOpenXml.Style;

namespace TestCaseExtractor
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow
    {
        private TfsTeamProjectCollection _tfs;
        ITestManagementTeamProject _testProject;
        ITestPlanCollection _testPlanCollection;
        private ITestSuiteBase _suite;
        int _i = 3;

        public MainWindow()
        {
            InitializeComponent();
        }

        void BtnConnect_Click(object sender, RoutedEventArgs e)
        {            
            _tfs = null;
            TbTfs.Text = null;
            var tpp = new TeamProjectPicker(TeamProjectPickerMode.SingleProject, false);
            tpp.ShowDialog();

            if (tpp.SelectedTeamProjectCollection == null) return;

            _tfs = tpp.SelectedTeamProjectCollection;
                
            var testService = (ITestManagementService)_tfs.GetService(typeof(ITestManagementService));

            _testProject = testService.GetTeamProject(tpp.SelectedProjects[0].Name);

            TbTfs.Text = _tfs.Name + "\\" + _testProject;

            _testPlanCollection = _testProject.TestPlans.Query("Select * from TestPlan");
               
            ProjectSelected_GetTestPlans();
        }

        private void BtnOpenFileDialog_Click(object sender, RoutedEventArgs e)
        {
            var saveFileDialog1 = new System.Windows.Forms.SaveFileDialog
            {
                InitialDirectory = Environment.SpecialFolder.MyDocuments.ToString(),
                Filter = Properties.Resources.MainWindow_BtnOpenFileDialog_Click,
                FilterIndex = 1
            };

            if (saveFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                TbFileName.Text = saveFileDialog1.FileName;
            }
            else
            {
                MessageBox.Show("Please choose a valid filename");
            }
        }

        private void ProjectSelected_GetTestPlans()
        {
            LbSelectTestPlan.ItemsSource = _testPlanCollection;
            LbSelectTestPlan.DisplayMemberPath = NameProperty.ToString();
            LbSelectTestPlan.SelectedIndex = -1;
        }

        private void LbSelectTestPlan_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            TvSuites.Items.Clear();
            GetTestSuites(LbSelectTestPlan.SelectedItem as ITestPlan);
        }

        void GetTestSuites(ITestPlan selectedTestPlan)
        {
            if (selectedTestPlan == null) return;
            var root = new TreeViewItem {Header = selectedTestPlan.RootSuite.Title};

            TvSuites.Items.Add(root);
            root.Tag = selectedTestPlan.RootSuite.Id;
                
            GetSubSuites(selectedTestPlan.RootSuite.SubSuites, root);
        }

        static void GetSubSuites(IEnumerable<ITestSuiteBase> subSuiteEntries, ItemsControl treeNode)
        {
            foreach (var suite in subSuiteEntries)
            {
                var suiteTree = new TreeViewItem {Header = suite.Title};
                treeNode.Items.Add(suiteTree);
                suiteTree.Tag = suite.Id;
                if (suite.TestSuiteType == TestSuiteType.StaticTestSuite)
                {
                    var suite1 = suite as IStaticTestSuite;
                    if (suite1.SubSuites.Count > 0)
                    {
                        GetSubSuites(suite1.SubSuites, suiteTree);
                    }
                }
            }
        }

        static string FindRootSuite(ITestSuiteBase currentSuite, string suiteTreePath)
        {
            var parentSuite = currentSuite.Parent;
            if (parentSuite == null) return suiteTreePath;
            if (parentSuite.IsRoot) return suiteTreePath;
            suiteTreePath = currentSuite.Parent.Title + ">" + suiteTreePath;
            var path = FindRootSuite(parentSuite, suiteTreePath);
            return path;
        }

        static string FindRootSuite(IRequirementTestSuite currentSuite, string suiteTreePath)
        {
            var parentSuite = currentSuite.Parent;
            if (parentSuite == null) return suiteTreePath;
            if (parentSuite.IsRoot) return suiteTreePath;
            suiteTreePath = currentSuite.Parent.Title + ">" + suiteTreePath;
            var path = FindRootSuite(parentSuite, suiteTreePath);
            return path;
        }

        private void BtnGenerate_Click(object sender, RoutedEventArgs e)
        {
            if (TbFileName.Text == null || TbFileName.Text.Length.Equals(0))
            {
                MessageBox.Show("Please Enter a valid file path");
            }
            else
            {
                _i = 3;
                if (TvSuites.SelectedValue != null)
                {
                    var tvItem = TvSuites.SelectedItem as TreeViewItem;

                    _suite = _testProject.TestSuites.Find(Convert.ToInt32(tvItem.Tag.ToString()));
                    
                    if (_suite != null)
                        Access_Excel(_suite);
                }
                else
                {
                    MessageBox.Show("Please select a test suite");
                }
            }   
        }

        void Access_Excel(ITestSuiteBase rootSuite)
        {
            try
            {
                var newFile = new FileInfo(TbFileName.Text);

                var template = new FileInfo(Directory.GetCurrentDirectory() + "\\Resources\\TestCaseTemplate.xlsx");
                using (var xlpackage = new ExcelPackage(newFile, template))
                {
                    ExcelWorksheet worksheet = xlpackage.Workbook.Worksheets[1];
                    worksheet.Name = (LbSelectTestPlan.SelectedItem as ITestPlan).RootSuite.Title;

                    worksheet.OutLineSummaryBelow = false;

                    WriteRootSuiteToExcel(rootSuite, worksheet);
                    if (rootSuite.TestSuiteType == TestSuiteType.StaticTestSuite)
                    {
                        GetTestSuites(rootSuite as IStaticTestSuite, worksheet);
                    }
                    if (rootSuite.TestSuiteType == TestSuiteType.RequirementTestSuite)
                    {
                        GetTestCases(rootSuite as IRequirementTestSuite, worksheet);
                    }

                    xlpackage.Save();

                    MessageBox.Show("File has been saved at " + TbFileName.Text);
                }
            }
            catch (Exception theException)
            {
                var errorMessage = "Error: ";
                errorMessage = String.Concat(errorMessage, theException.Message);
                errorMessage = String.Concat(errorMessage, " Line: ");
                errorMessage = String.Concat(errorMessage, theException.Source);

                MessageBox.Show(errorMessage, "Error");
            }
        }

        void WriteRootSuiteToExcel(ITestSuiteBase testSuite, ExcelWorksheet worksheet)
        {
            worksheet.Cells[1, 1].Value = _testProject+": "+testSuite.Title;
        }

        void WriteSuiteToExcel(ITestSuiteEntry testSuite, ExcelWorksheet worksheet)
        {
            worksheet.Cells[_i, 1].Style.Fill.PatternType = ExcelFillStyle.Solid;
            worksheet.Cells[_i, 1].Style.Fill.BackgroundColor.SetColor(Color.CornflowerBlue);
            worksheet.Cells[_i, 1].Style.Font.Bold = true;
            worksheet.Cells[_i, 2].Style.Fill.PatternType = ExcelFillStyle.Solid;
            worksheet.Cells[_i, 2].Style.Fill.BackgroundColor.SetColor(Color.CornflowerBlue);
            worksheet.Cells[_i, 3].Style.Fill.PatternType = ExcelFillStyle.Solid;
            worksheet.Cells[_i, 3].Style.Fill.BackgroundColor.SetColor(Color.CornflowerBlue);
            worksheet.Cells[_i, 4].Style.Fill.PatternType = ExcelFillStyle.Solid;
            worksheet.Cells[_i, 4].Style.Fill.BackgroundColor.SetColor(Color.CornflowerBlue);
            worksheet.Cells[_i, 5].Style.Fill.PatternType = ExcelFillStyle.Solid;
            worksheet.Cells[_i, 5].Style.Fill.BackgroundColor.SetColor(Color.CornflowerBlue);

            worksheet.Cells[_i, 1].Value = FindRootSuite(testSuite.TestSuite as IStaticTestSuite, testSuite.Title);
        }

        void WriteSuiteToExcel(IRequirementTestSuite testSuite, ExcelWorksheet worksheet)
        {
            worksheet.Cells[_i, 1].Style.Fill.PatternType = ExcelFillStyle.Solid;
            worksheet.Cells[_i, 1].Style.Fill.BackgroundColor.SetColor(Color.LightBlue);
            worksheet.Cells[_i, 1].Style.Font.Bold = true;
            worksheet.Cells[_i, 2].Style.Fill.PatternType = ExcelFillStyle.Solid;
            worksheet.Cells[_i, 2].Style.Fill.BackgroundColor.SetColor(Color.LightBlue);
            worksheet.Cells[_i, 3].Style.Fill.PatternType = ExcelFillStyle.Solid;
            worksheet.Cells[_i, 3].Style.Fill.BackgroundColor.SetColor(Color.LightBlue);
            worksheet.Cells[_i, 4].Style.Fill.PatternType = ExcelFillStyle.Solid;
            worksheet.Cells[_i, 4].Style.Fill.BackgroundColor.SetColor(Color.LightBlue);
            worksheet.Cells[_i, 5].Style.Fill.PatternType = ExcelFillStyle.Solid;
            worksheet.Cells[_i, 5].Style.Fill.BackgroundColor.SetColor(Color.LightBlue);

            worksheet.Cells[_i, 1].Value = FindRootSuite(testSuite, testSuite.Title);
        }

        void WriteTestCaseToExcel(ITestBase testCase, ExcelWorksheet worksheet)
        {
            worksheet.Cells[_i, 2].Style.Fill.PatternType = ExcelFillStyle.Solid;
            worksheet.Cells[_i, 2].Style.Fill.BackgroundColor.SetColor(Color.Yellow);
            worksheet.Cells[_i, 2].Style.Font.Bold = true;
            worksheet.Cells[_i, 3].Style.Fill.PatternType = ExcelFillStyle.Solid;
            worksheet.Cells[_i, 3].Style.Fill.BackgroundColor.SetColor(Color.Yellow);
            worksheet.Cells[_i, 3].Style.Font.Bold = true;
            worksheet.Cells[_i, 4].Style.Fill.PatternType = ExcelFillStyle.Solid;
            worksheet.Cells[_i, 4].Style.Fill.BackgroundColor.SetColor(Color.Yellow);
            worksheet.Cells[_i, 4].Style.Font.Bold = true;
            worksheet.Cells[_i, 5].Style.Fill.PatternType = ExcelFillStyle.Solid;
            worksheet.Cells[_i, 5].Style.Fill.BackgroundColor.SetColor(Color.Yellow);
            worksheet.Cells[_i, 5].Style.Font.Bold = true;

            worksheet.Cells[_i, 2].Value = testCase.Id.ToString();
            worksheet.Cells[_i, 3].Value = testCase.Title+" : "+testCase.CustomFields.TryGetById(10075).Value;
            worksheet.Cells[_i, 4].Value = "Steps:";
            worksheet.Cells[_i, 5].Value = "Expected Results";

            worksheet.Row(_i).OutlineLevel = 1;

            var j = 1;

            foreach (ITestAction action in testCase.Actions)
            {
                var sharedRef = action as ISharedStepReference;

                string testAction;
                string expectedResult;
                if (sharedRef != null)
                {
                    var sharedStep = sharedRef.FindSharedStep();
                    foreach (var testStep in sharedStep.Actions.Select(sharedAction => sharedAction as ITestStep))
                    {
                        testAction = j.ToString() + ". " +
                                     ((testStep.Title.ToString().Length == 0)
                                         ? "<<Not Recorded>>"
                                         : testStep.Title.ToString());
                        expectedResult = ((testStep.ExpectedResult.ToString().Length == 0)
                            ? "<<Not Recorded>>"
                            : testStep.ExpectedResult.ToString());
                        WriteTestStepsToExcel(worksheet, _i, j, StripTagsCharArray(testAction), StripTagsCharArray(expectedResult));
                        j++;
                    }
                }
                else
                {
                    var testStep = action as ITestStep;
                    testAction = j.ToString() + ". " +
                                 ((testStep.Title.ToString().Length == 0)
                                     ? "<<Not Recorded>>"
                                     : testStep.Title.ToString());
                    expectedResult = ((testStep.ExpectedResult.ToString().Length == 0)
                        ? "<<Not Recorded>>"
                        : testStep.ExpectedResult.ToString());

                    WriteTestStepsToExcel(worksheet, _i, j, StripTagsCharArray(testAction), StripTagsCharArray(expectedResult));
                    j++;
                }
            } //end of foreach test action
            _i = _i + j - 1;
        }

        static void WriteTestStepsToExcel(ExcelWorksheet worksheet, int i, int j, string testAction, string expectedResult)
        {
            worksheet.Cells[i + j, 4].Value = testAction;
            worksheet.Cells[i + j, 5].Value = expectedResult;
            
            worksheet.Row(i + j).OutlineLevel = 2;
        }

        private void GetTestCases(IRequirementTestSuite requirementTestSuite, ExcelWorksheet worksheet)
        {
            WriteSuiteToExcel(requirementTestSuite, worksheet);
            _i++;
            foreach (var testCase in requirementTestSuite.AllTestCases)
            {
                WriteTestCaseToExcel(testCase, worksheet);
                _i++;
            }
        }

        private void GetTestSuites(IStaticTestSuite staticTestSuite, ExcelWorksheet worksheet)
        {
            foreach (var suiteEntry in staticTestSuite.Entries.Where(suiteEntry => suiteEntry.EntryType == TestSuiteEntryType.TestCase))
            {
                WriteTestCaseToExcel(suiteEntry.TestCase, worksheet);
                _i++;
            }

            foreach (var suiteEntry in staticTestSuite.Entries.Where(suiteEntry => suiteEntry.EntryType == TestSuiteEntryType.StaticTestSuite || 
                                                                                   suiteEntry.EntryType == TestSuiteEntryType.RequirementTestSuite))
            {
                if (suiteEntry.EntryType == TestSuiteEntryType.StaticTestSuite)
                {
                    var suite = suiteEntry.TestSuite as IStaticTestSuite;
                    WriteSuiteToExcel(suiteEntry, worksheet);
                    _i++;
                    if (suite.Entries.Count > 0)
                    {
                        GetTestSuites(suite, worksheet);
                    }
                }
                else
                {
                    var suite = suiteEntry.TestSuite as IRequirementTestSuite;
                    GetTestCases(suite, worksheet);
                }
            }
        }

        public static string StripTagsCharArray(string source)
        {
            var correctString = source.Replace("&nbsp;", " ");
            var array = new char[correctString.Length];
            var arrayIndex = 0;
            var inside = false;

            foreach (var letter in correctString)
            {
                if (letter == '<')
                {
                    inside = true;
                    continue;
                }
                if (letter == '>')
                {
                    inside = false;
                    continue;
                }
                if (inside) continue;
                array[arrayIndex] = letter;
                arrayIndex++;
            }
            return new string(array, 0, arrayIndex);
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {

        }
    }
}